﻿using System;
using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TfsBuildLauncher.Tests
{
    [TestClass]
    public class ArgumentsParserTests
    {
        [TestMethod]
        public void Parse_EmptyArgs_IsValid()
        {
            var arguments = new ArgumentsParser(new string[] { });
            arguments.Parse();
            Assert.AreEqual(true, arguments.IsValid, "Arguments should be valid if there are none");
        }


        [TestMethod]
        public void Arg_GetValueWhenNotParsedAndRequired_ReturnErrors()
        {
            var arguments = new ArgumentsParser(new string[] { });
            Arg<string> nameArg = arguments.Declare<string>("name", IsRequired: true);
            try
            {
                Console.WriteLine(nameArg.Value);
                Assert.Fail("An exception should have been raised");
            }
            catch (InvalidOperationException ex)
            {
                Assert.IsTrue(ex.Message.Contains("name"), "Error message should contain \"name\"");
                Assert.IsTrue(ex.Message.Contains("has not been initialized"), "Error message should contain \"has not been initialized\"");
            }
        }

        [TestMethod]
        public void Arg_GetValuesWhenNotParsed_ReturnErrors()
        {
            var arguments = new ArgumentsParser(new string[] { });
            Arg<string> nameArg = arguments.Declare<string>("name", IsRequired: true);
            try
            {
                Console.WriteLine(nameArg.Values);
                Assert.Fail("An exception should have been raised");
            }
            catch (InvalidOperationException ex)
            {
                Assert.IsTrue(ex.Message.Contains("name"), "Error message should contain \"name\"");
                Assert.IsTrue(ex.Message.Contains("has not been initialized"), "Error message should contain \"has not been initialized\"");
            }
        }

        [TestMethod]
        public void Parse_MissingRequiredArgument_ReturnsErrors()
        {
            var arguments = new ArgumentsParser(new string[] { });
            Arg<string> nameArg = arguments.Declare<string>("vulkor44", IsRequired: true);
            arguments.Parse();
            Assert.AreEqual(false, arguments.IsValid, "Argments parser should be in an invalid state");
            Assert.IsTrue(arguments.ErrorMessage.Contains("vulkor44"), "ErrorMessage should contain the name of the missing argument.");
        }

        [TestMethod]
        public void Parse_WithSimpleString_GetCorrectValue()
        {
            var arguments = new ArgumentsParser(new string[] { "/name:theValue" });
            Arg<string> result = arguments.Declare<string>("name");
            arguments.Parse();
            Assert.AreEqual("theValue", result.Value, "should have found theValue");
        }

        [TestMethod]
        public void Parse_WithMultipleTypes_GetCorrectValues()
        {
            var arguments = new ArgumentsParser(new string[] { "/name:theValue", "/age:124232", "/url:http://localhost:8080/tfs", "/b:true" });
            Arg<string> nameArg = arguments.Declare<string>("name");
            Arg<int> ageArg = arguments.Declare<int>("age");
            Arg<Uri> urlArg = arguments.Declare<Uri>("url");
            Arg<bool> boolArg = arguments.Declare<bool>("b");
            arguments.Parse();
            Assert.AreEqual("theValue", nameArg.Value, "Should have found name = theValue");
            Assert.AreEqual(124232, ageArg.Value, "Should have found age = 124232");
            Assert.AreEqual(new Uri("http://localhost:8080/tfs"), urlArg.Value, "Should have found url = http://localhost:8080/tfs");
            Assert.AreEqual(true, boolArg.Value, "Should have found b is true");
        }

        [TestMethod]
        public void Parse_UndeclaredArgumentFound_ReturnsErrors()
        {
            var arguments = new ArgumentsParser(new string[] { "anchor/yazhaar" });
            arguments.Parse();
            Assert.AreEqual(false, arguments.IsValid, "Argments parser should be in an invalid state");
            Assert.IsTrue(arguments.ErrorMessage.Contains("anchor/yazhaar"), "ErrorMessage should contain the name of the invalid argument.");
        }

        [TestMethod]
        public void Parse_WithListOfValues_GetCorrectValues()
        {
            var arguments = new ArgumentsParser(new string[] { "/prop:theValue1", "/prop:12411,33", "/prop:yoh bih" });
            Arg<string> result = arguments.Declare<string>("prop", IsList: true);
            arguments.Parse();
            Assert.IsTrue(result.Values.Contains("theValue1"), "Should have found theValue1");
            Assert.IsTrue(result.Values.Contains("12411,33"), "Should have found 12411");
            Assert.IsTrue(result.Values.Contains("yoh bih"), "Should have found yoh bih");
        }

    }
}
